// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
const vscode = require("vscode");
const encodeMethod = require("text-encoding");

// this method is called when your extension is activated
// your extension is activated the very first time the command is executed

const replace_text_from_selected_files_prompt_first =
  "Enter the text you want to replace:";
const replace_text_from_selected_files_prompt_second =
  "Enter the text you want to tranfer:";
const replace_text_from_selected_files_placeholder_third =
  "Select your target files:";
const replace_text_filename_filt_by_pattern_placeholder =
  "Enter the pattern to exclude the files you don't want to Operate";
const replace_text_filename_filt_by_pattern_placeholder_prompt = [
  "A file glob pattern to match file paths against. This can either be a glob pattern string (like **/*.{ts,js} or *.{ts,js}) or a relative pattern.",
  "Glob patterns can have the following syntax:",
  "* to match one or more characters in a path segment",
  "? to match on one character in a path segment",
  "** to match any number of path segments, including none",
  "{} to group conditions (e.g. **/*.{ts,js} matches all TypeScript and JavaScript files)",
  "[] to declare a range of characters to match in a path segment (e.g., example.[0-9] to match on example.0, example.1, …)",
  "[!...] to negate a range of characters to match in a path segment (e.g., example.[!0-9] to match on example.a, example.b, but not example.0)",
  "Note: a backslash (\\) is not valid within a glob pattern. If you have an existing file path to match against, consider to use the relative pattern support that takes care of converting any backslash into slash. Otherwise, make sure to convert any backslash to slash when creating the glob pattern.",
].toString();

const action_revert_or_redo = "Are you sure you want to {} the last action?";
const action_redo = "Redo";
const action_revert = "Revert";
const action_none = "Nothing";

const selection_keep = "It looks guud, i'll keep it.";
const selection_do = "I regreted, so I want to {} it";

const err_workspace_not_writable = "your workspace is not writable!";
const err_workspace_not_is_trust = "your workspace is not in trusted mode!";
const err_regret_no_history_error =
  "Can't get the last action record! Did you shut down or restart the VSC after the last action?";
const err_file_update_error =
  "updating {} failed, another {} flie(s) hasn't transformd!";

const success_update = "{} file(s) updated success! Updated File list: {}";

const default_picked = false;

// @ts-ignore
const encode = "utf-8";

const encoder = new encodeMethod.TextEncoder(encode);
const decoder = new encodeMethod.TextDecoder(encode);

const fs = vscode.workspace.fs;

function isOperational() {
  if (fs.isWritableFileSystem && vscode.workspace.isTrusted) {
    return true;
  } else if (!fs.isWritableFileSystem) {
    vscode.window.showErrorMessage(err_workspace_not_writable);
    return false;
  } else if (!vscode.workspace.isTrusted) {
    vscode.window.showErrorMessage(err_workspace_not_is_trust);
    return false;
  }
}

var beforeEnhancedReplaceData = [];

var afterEnhancedReplaceData = [];

var targetText = "";

var transformedText = "";

var pattern = "";

var recentExcludePattern = "";

function isRegretable() {
  const result =
    isOperational() &&
    beforeEnhancedReplaceData.length > 0 &&
    afterEnhancedReplaceData.length > 0;
  if (!result) {
    vscode.window.showErrorMessage(err_regret_no_history_error);
  }
  return result;
}

/**
 * @param {{ subscriptions: vscode.Disposable[]; }} context
 */
function activate(context) {
  // Use the console to output diagnostic information (console.log) and errors (console.error)
  // This line of code will only be executed once when your extension is activated
  // console.log('Congratulations, your extension "replace-text-from-selected-files" is now active!');

  // The command has been defined in the package.json file
  // Now provide the implementation of the command with  registerCommand
  // The commandId parameter must match the command field in package.json

  let replaceMethod1 = vscode.commands.registerCommand(
    "replace-text-enhanced.replace-text-from-selected-files",
    function () {
      // The code you place here will be executed every time your command is executed
      if (!isOperational()) return;

      vscode.workspace.findFiles("").then((files) => {
        var selection = new Array();
        files.forEach((element) => {
          selection.push({
            alwaysShow: true,
            desciption: element.fsPath,
            detail: element.path,
            label:
              "workspace@" +
              vscode.workspace.name +
              ": " +
              element.path.substring(element.path.lastIndexOf("/")),
            picked: default_picked,
          });
        });
        vscode.window
          .showInputBox({
            ignoreFocusOut: true,
            prompt: replace_text_filename_filt_by_pattern_placeholder_prompt,
            // prompt: replace_text_from_selected_files_prompt_first
          })
          .then((target) => {
            // console.log(target);
            if (target === undefined) return;
            vscode.window
              .showInputBox({
                ignoreFocusOut: true,
                prompt: replace_text_from_selected_files_prompt_second,
              })
              .then((transfer) => {
                if (transfer === undefined) return;
                // console.log(transfer);
                vscode.window
                  .showQuickPick(selection, {
                    ignoreFocusOut: true,
                    title: replace_text_from_selected_files_placeholder_third,
                    canPickMany: true,
                  })
                  .then((fileList) => {
                    if (fileList === undefined) return;
                    targetText = target;
                    transformedText = transfer;
                    // var filenames = new Array();
                    // console.log(fileList);
                    // fileList.forEach((file) => {
                    //   try {
                    //     // let original = filesys.readFileSync(file.detail,encode);
                    //     // original.replace(target, transfer);
                    //     fs.readFile(vscode.Uri.parse(file.detail)).then(
                    //       (array) => {
                    //         // console.log(array);
                    //         var original = "";
                    //         original = decoder.decode(array);
                    //         //do: replace
                    //         var result = original.replaceAll(target, transfer);
                    //         if (original == result) return;
                    //         //Data record: before Replace
                    //         beforeEnhancedReplaceData.push({
                    //           uri: vscode.Uri.parse(file.detail),
                    //           before: original,
                    //           filename: file.label,
                    //         });
                    //         fs.writeFile(
                    //           vscode.Uri.parse(file.detail),
                    //           encoder.encode(result)
                    //         );
                    //         //Data record: after replace
                    //         afterEnhancedReplaceData.push({
                    //           uri: vscode.Uri.parse(file.detail),
                    //           after: result,
                    //           filename: file.label,
                    //         });
                    //         filenames.push(file.label);
                    //       }
                    //     );
                    //     vscode.window.showInformationMessage(
                    //       success_update
                    //         .replace("{}", fileList.length.toString())
                    //         .replace("{}", filenames.toString())
                    //     );
                    //     // filesys.writeFileSync(file.detail, original);
                    //   } catch (error) {
                    //     console.log(error);
                    //     const size =
                    //       fileList.length - fileList.indexOf(file) - 1;
                    //     var errmsg = new String(
                    //       err_file_update_error
                    //     ).toString();
                    //     vscode.window.showErrorMessage(
                    //       errmsg
                    //         .replace("{}", file.label)
                    //         .replace("{}", size.toString())
                    //     );
                    //     return;
                    //   }
                    // });
                    return executeUpdate(fileList, target, transfer);
                  });
              });
          });
      });
    }
  );

  let replaceMethod2 = vscode.commands.registerCommand(
    "replace-text-enhanced.replace-text-filename-filt-by-pattern",
    function () {
      vscode.window.showInformationMessage(
        "Replace Text(Filename filt by reg.)"
      );
    }
  );

  let replaceMethod3 = vscode.commands.registerCommand(
    "replace-text-enhanced.replace-text-from-selected-files-with-exclusion",
    function () {
      if (!isOperational()) return;
      vscode.window.showInformationMessage(
        "into: replace-text-enhanced.replace-text-from-selected-files-with-exclusion"
      );
    }
  );

  let replaceMethod4 = vscode.commands.registerCommand(
    "replace-text-enhanced.replace-text-filename-filt-by-pattern-with-exclusion",
    function () {
      if (!isOperational()) return;
      vscode.window.showInformationMessage(
        "into: replace-text-enhanced.replace-text-filename-filt-by-pattern-with-exclusion"
      );
    }
  );

  let replaceMethod5 = vscode.commands.registerCommand(
    "replace-text-enhanced.revert-recent-enhanced-replace-operation",
    function () {
      if (!isRegretable()) return;
      const items = [
        { label: action_none, desciption: "false", detail: selection_keep },
        {
          label: action_revert,
          desciption: "true",
          detail: selection_do.replace("{}", action_revert.toLowerCase()),
        },
      ];
      vscode.window
        .showQuickPick(items, {
          title: action_revert_or_redo.replace(
            "{}",
            action_revert.toLowerCase()
          ),
        })
        .then((item) => {
          if (!item === undefined || item.desciption == "false") return;
          else if (item.desciption == "true") {
            var filenames = new Array();
            var before = new Array();
            var after = new Array();
            beforeEnhancedReplaceData.forEach((record) => {
              var changedValue =
                afterEnhancedReplaceData[
                  beforeEnhancedReplaceData.indexOf(record)
                ];
              if (record.before == changedValue.after) {
                return;
              } else
                try {
                  //Data record: before Replace
                  before.push({
                    uri: record.uri,
                    before: changedValue.after,
                    filename: record.filename,
                  });
                  //do: replace

                  fs.writeFile(record.uri, encoder.encode(record.before));
                  //Data record: after replace
                  after.push({
                    uri: record.uri,
                    after: record.before,
                    filename: record.filename,
                  });
                  filenames.push(record.filename);

                  vscode.window.showInformationMessage(
                    success_update
                      .replace(
                        "{}",
                        beforeEnhancedReplaceData.length.toString()
                      )
                      .replace("{}", filenames.toString())
                  );
                  // filesys.writeFileSync(file.detail, original);
                } catch (error) {
                  console.log(error);
                  const size =
                    beforeEnhancedReplaceData.length -
                    beforeEnhancedReplaceData.indexOf(record) -
                    1;
                  var errmsg = new String(err_file_update_error).toString();
                  vscode.window.showErrorMessage(
                    errmsg
                      .replace("{}", record.filenamel)
                      .replace("{}", size.toString())
                  );
                  return;
                }
            });
            beforeEnhancedReplaceData = before;
            afterEnhancedReplaceData = after;
          }
        });
    }
  );

  let replaceMethod6 = vscode.commands.registerCommand(
    "replace-text-enhanced.redo-recent-enhanced-replace-operation",
    function () {
      if (!isRegretable()) return;
      // vscode.window.showInformationMessage("into: replace-text-enhanced.redo-recent-enhanced-replace-operation");
      const items = [
        { label: action_none, desciption: "false", detail: selection_keep },
        {
          label: action_redo,
          desciption: "true",
          detail: selection_do.replace("{}", action_redo.toLowerCase()),
        },
      ];
      vscode.window
        .showQuickPick(items, {
          title: action_revert_or_redo.replace("{}", action_redo.toLowerCase()),
        })
        .then((item) => {
          if (!item === undefined || item.desciption == "false") return;
          else if (item.desciption == "true") {
            vscode.workspace.findFiles(pattern?pattern:"").then((files) => {
              // FIXME: unfinish
            })
            // var filenames = new Array();
            // var before = new Array();
            // var after = new Array();
            // beforeEnhancedReplaceData.forEach((record) => {
            //   try {
            //     // let original = filesys.readFileSync(file.detail,encode);
            //     // original.replace(target, transfer);
            //     fs.readFile(record.uri).then((array) => {
            //       // console.log(array);
            //       var original = "";
            //       original = decoder.decode(array);
            //       //do: replace
            //       var result = original.replaceAll(targetText, transformedText);
            //       if (original == result) return;
            //       //Data record: before Replace
            //       before.push({
            //         uri: record.uri,
            //         before: original,
            //         filename: record.filename,
            //       });
            //       fs.writeFile(record.uri, encoder.encode(result));
            //       //Data record: after replace
            //       after.push({
            //         uri: record.uri,
            //         after: original,
            //         filename: record.filename,
            //       });
            //       filenames.push(record.filename);
            //     });
            //     vscode.window.showInformationMessage(
            //       success_update
            //         .replace("{}", beforeEnhancedReplaceData.length.toString())
            //         .replace("{}", filenames.toString())
            //     );
            //     // filesys.writeFileSync(file.detail, original);
            //   } catch (error) {
            //     console.log(error);
            //     const size =
            //       beforeEnhancedReplaceData.length -
            //       beforeEnhancedReplaceData.indexOf(record) -
            //       1;
            //     var errmsg = new String(err_file_update_error).toString();
            //     vscode.window.showErrorMessage(
            //       errmsg
            //         .replace("{}", record.filenamel)
            //         .replace("{}", size.toString())
            //     );
            //     return;
            //   }
            // });
            // beforeEnhancedReplaceData = before;
            // afterEnhancedReplaceData = after;
          }
        });
    }
  );

  context.subscriptions.push(replaceMethod1);
  context.subscriptions.push(replaceMethod2);
  context.subscriptions.push(replaceMethod3);
  context.subscriptions.push(replaceMethod4);
  context.subscriptions.push(replaceMethod5);
  context.subscriptions.push(replaceMethod6);
}

/**
 * @param {any[]} fileList
 * @param {string} targetText
 * @param {string} transformedText
 * @param {string | ?} excludePattern
 */
function executeUpdate(fileList, targetText, transformedText, excludePattern) {
  var filenames = new Array();
  var before = new Array();
  var after = new Array();
  fileList.forEach((file) => {
    try {
      fs.readFile(vscode.Uri.parse(file.detail)).then((array) => {
        // console.log(array);
        var original = "";
        original = decoder.decode(array);

        var result = "";
        //do: replace
        if (!excludePattern || original.indexOf(excludePattern) == -1) {
          if (excludePattern) recentExcludePattern = excludePattern;
          result = original.replaceAll(targetText, transformedText);
          if (original == result) return;
        } else {
          //replace with excludePattern
          recentExcludePattern = excludePattern;
          var beforeReplace = new String(original);
          while (true) {
            var indexOfExclusion = original.indexOf(excludePattern);
            if (indexOfExclusion == -1) {
              result =
                result + original.replaceAll(targetText, transformedText);
              break;
            } else {
              var replacable = original.substring(0, indexOfExclusion);
              result += replacable + excludePattern;
              original = original.substring(
                0,
                indexOfExclusion + excludePattern.length
              );
            }
          }
          if (beforeReplace.toString() == result) return;
          //Data record: before Replace
          beforeEnhancedReplaceData.push({
            uri: vscode.Uri.parse(file.detail),
            before: beforeReplace,
            filename: file.label,
          });
        }
        fs.writeFile(vscode.Uri.parse(file.detail), encoder.encode(result));
        //Data record: after replace
        afterEnhancedReplaceData.push({
          uri: vscode.Uri.parse(file.detail),
          after: result,
          filename: file.label,
        });
        filenames.push(file.label);
      });
      vscode.window.showInformationMessage(
        success_update
          .replace("{}", fileList.length.toString())
          .replace("{}", filenames.toString())
      );
    } catch (error) {
      console.log(error);
      const size =
        beforeEnhancedReplaceData.length -
        beforeEnhancedReplaceData.indexOf(file) -
        1;
      var errmsg = new String(err_file_update_error).toString();
      beforeEnhancedReplaceData = before;
      afterEnhancedReplaceData = after;
      vscode.window.showErrorMessage(
        errmsg.replace("{}", file.label).replace("{}", size.toString())
      );
      return;
    }
  });
  beforeEnhancedReplaceData = before;
  afterEnhancedReplaceData = after;
}

// this method is called when your extension is deactivated
function deactivate() {}

module.exports = {
  activate,
  deactivate,
};
